package net.youdi.gateway.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import lombok.extern.slf4j.Slf4j;
import net.youdi.gateway.exception.GateWayException;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.reactive.function.server.*;

import java.util.Map;

/**
 * @author:scl
 * @date:2019-05-17 14:24
 * @description
 */
@Slf4j(topic = "gateway.error")
public class GateWayJsonExceptionHandler extends DefaultErrorWebExceptionHandler {
    /**
     * Create a new {@code DefaultErrorWebExceptionHandler} instance.
     *
     * @param errorAttributes    the error attributes
     * @param resourceProperties the resources configuration properties
     * @param errorProperties    the error configuration properties
     * @param applicationContext the current application context
     */
    public GateWayJsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }

    /**
     * 获取异常属性
     *
     * @param request
     * @param includeStackTrace
     * @return 如果是网关自定义异常，则返回自定义数据，否则默认方式处理
     */
    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
        Throwable error = super.getError(request);
        log.error("网关错误异常------->",error);
        Map<String, Object> errorAttributes = super.getErrorAttributes(request, includeStackTrace);
        if (error instanceof GateWayException){
            errorAttributes.put("code",((GateWayException)error).getCode());
        }else {
            //由于该异常处理器的优先级比SentinelGatewayBlockExceptionHandler优先级高，
            //所以所有异常错误会直接来该处理器
            //如果还想使用SentinelGatewayBlockExceptionHandler,则在生命bean的时候将该处理器优先级调低即可
            if(BlockException.isBlockException(error)){
                errorAttributes.put("code",HttpStatus.TOO_MANY_REQUESTS.value());
                errorAttributes.put("message","服务器压力大，请稍后再试^^");
            }else{
                errorAttributes.put("message","系统开小差了^^");
                errorAttributes.put("code", error instanceof WebClientResponseException ? ((WebClientResponseException)error).getStatusCode().value() : HttpStatus.INTERNAL_SERVER_ERROR.value());
            }
        }
        return errorAttributes;
    }

    /**
     * 指定响应处理方法为JSON处理的方法
     *
     * @param errorAttributes
     */
    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    /**
     * 根据code获取对应的HttpStatus
     *
     * @param errorAttributes
     */

    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {
        return HttpStatus.OK.value();
//        return super.getHttpStatus(errorAttributes);
    }
}
